#include <xc.inc>
    psect   intentry, class=CODE, delta=2
    psect   reset_vec, class=CODE, delta=2
    psect   eeprom_data,class=EEDATA,delta=2,space=3,noexec
    psect   powerup, class=CODE, delta=2
    psect   cinit,class=CODE,delta=2
    psect   functab,class=ENTRY,delta=2
    psect   idloc,class=IDLOC,delta=2,noexec

    global _main, reset_vec
    
psect config, class=CONFIG, delta=2
#ifndef BOOTLOADER
    dw	0xDFEC
    dw	0xF7FF
    dw	0xFFBF
    dw	0xEFFE
    dw	0xFFFF
#endif
    
    psect	reset_vec
reset_vec:
    ljmp	_main


;GLOBAL VARIABLES
    psect	CommonVar, class=COMMON, space=1, delta=1
;main
dis_cache:	ds 4
delay1:	ds 1
delay2:	ds 1
;debounce
last_result:	ds 1
count:		ds 1
;status_trans
action:	ds 1
state:		ds 1
event:		ds 1
wait_count:	ds 1
click_count:  ds 1
last_key:	ds 1
;connection_check
index:		ds 1
;global
cur_key:	ds 1
    psect	udata
i:		ds 1
j:		ds 1
led_select:	ds 1
workplace2:	ds 1
dis_last_key:	ds 1
dis_count:	ds 2
swap:		ds 1
press_count:ds 1


;STATIC TABLE
    psect	Table, class=CODE, delta=2
event_table: 
    MOVWF        PCL
IRP event,1,0,3,0,1,1,0,1,2,1,4,4,0,3,4
    RETLW   event
ENDM

action_table: 
    MOVWF        PCL 
IRP row_click,0b1111,0b101,0b1010,0b0,0b1111
    RETLW   row_click
ENDM
IRP row_wait,0b1111,0b101,0b1111,0b10100,0b0
    RETLW   row_wait
ENDM
IRP row_press,0b1111,0b1111,0xff,0b1010,0b1111
    RETLW   row_press
ENDM
IRP row_init,0b1111,0b1111,0xff,0b0,0b0
    RETLW   row_init
ENDM
IRP row_double,0b1111,0b1111,0xff,0b10100,0b1111
    RETLW   row_double
ENDM

seq_table:
    ADDWF        PCL,f
IRP seq_num,0b00111111,0b00000110,0b01011011,0b01001111,0b01100110,0b01101101,0b01111101,0b00000111,0b01111111,0b01101111,0b01110111
    RETLW    seq_num
ENDM
    
code_table:
    MOVWF PCL
IRP code_num,0b00000111,0b00001011,0b00001101,0b00001110
    RETLW   code_num
ENDM

key_table: 
    ADDWF        PCL,F   
IRP key_num,5,1,2,3,4,6
    RETLW   key_num
ENDM


;INTERRUPT SERVICE
    psect intentry
intentry:
	;clear the signal bit
	BANKSEL PIR0
	BCF PIR0,5
    
	;init the TMR0 offset
	BANKSEL TMR0L
	;MOCLW 0xfec0c
	MOVLW 0xec
	MOVWF TMR0H
	MOVLW 0x78
	MOVWF TMR0L
    
    connection_check:
    CLRF cur_key
    BANKSEL i
    MOVLW 1
    MOVWF i
    CLRF index
    BANKSEL TRISB
    MOVLW 0x0f
    MOVWF TRISB
    BANKSEL WPUB
    MOVLW 0x0f
    MOVWF WPUB
jedge_i_16:
    BANKSEL i
    BTFSS i,4
    GOTO i_unequ_16
    GOTO i_equ_16
    
i_unequ_16:
    BANKSEL i
    MOVF i, W
    BANKSEL PORTB
    ANDWF PORTB, W

    BANKSEL workplace2
    MOVWF workplace2
    MOVF workplace2,f
    BTFSS STATUS,2 
    GOTO branch1_portb_unequ_0
    GOTO branch1_portb_equ_0
    
i_equ_16:
    MOVF cur_key, f
    BTFSS STATUS,2
    GOTO trunk_curkey_unequ_0
    GOTO trunk_curkey_equ_0
    
branch1_portb_equ_0:
    MOVF cur_key,f
    BTFSS STATUS,2
    GOTO branch1_curkey_unequ_0
    GOTO branch1_curkey_equ_0
    
branch1_portb_unequ_0:
    BANKSEL i
    LSLF i, f
    INCF index,f
    GOTO jedge_i_16
    
branch1_curkey_unequ_0:
    MOVLW 255
    MOVWF cur_key
    GOTO trunk_curkey_unequ_0
    
branch1_curkey_equ_0:
    MOVLW 7
    ADDWF index, W
    MOVWF cur_key
    GOTO branch1_portb_unequ_0
    
trunk_curkey_unequ_0:
    GOTO debounce

trunk_curkey_equ_0:
    BANKSEL i
    MOVLW 1
    MOVWF i
    MOVLW 2
    MOVWF j
    CLRF index
jedge_i_8:
    BTFSS i, 3
    GOTO i_unequ_8
    GOTO i_equ_8

i_unequ_8:
    MOVF j, w
    BTFSS j, 4
    GOTO j_unequ_16
    GOTO j_equ_16
    
i_equ_8:
    GOTO trunk_curkey_unequ_0
    
j_unequ_16:
    BANKSEL j
    COMF j, W
    BANKSEL TRISB
    MOVWF TRISB
    BANKSEL WPUB
    MOVWF WPUB
    BANKSEL PORTB
    MOVWF PORTB
    
    BANKSEL i
    MOVF i, W
    BANKSEL PORTB
    ANDWF PORTB, W

    BANKSEL workplace2
    MOVWF workplace2
    MOVF workplace2,F
    BTFSS STATUS,2 
    GOTO branch2_portb_unequ_0
    GOTO branch2_portb_equ_0
    
j_equ_16:
    BANKSEL i
    LSLF i, f
    LSLF i, W
    MOVWF j
    GOTO jedge_i_8
    
    
branch2_portb_equ_0:
    MOVF cur_key,F 
    BTFSS STATUS,2 
    GOTO branch2_curkey_unequ_0
    GOTO branch2_curkey_equ_0
    
branch2_portb_unequ_0:
    LSLF j, f
    INCF index, f
    GOTO i_unequ_8
    
branch2_curkey_equ_0:
    ;cur_key = key_table[index]
    MOVLW HIGH(key_table)
    MOVWF PCLATH  
    MOVF index,W
    CALL key_table
    MOVWF cur_key
    GOTO j_equ_16
    
branch2_curkey_unequ_0:
    MOVLW 255
    MOVWF cur_key
    GOTO i_equ_8

debounce:
    MOVF    last_result, W
    XORWF   cur_key, W
    BTFSC   STATUS, 2
    GOTO    deb_continue    ;no shake
    INCF    count	    ;shake
    MOVLW   2
    XORWF   count, W
    BTFSS   STATUS, 2
    GOTO    deb_ignore	    ;not equ
    MOVF    cur_key, W;equ
    MOVWF   last_result
    GOTO    deb_continue
    
deb_ignore:
    MOVF    last_result, W
    MOVWF   cur_key
    GOTO    transfer
    
deb_continue:
    CLRF    count
    GOTO transfer
    
    
transfer:
;key value
    MULTI	EQU 0xFF
    NOKEY	EQU 0
;action index
    MULTIKEY	EQU 0
    UP		EQU 1
    TIMEOUT	EQU 2
    SAME	EQU 3
    OTHER	EQU 4
;state value
    CLICK	EQU 0
    WAIT	EQU 5
    PRESS	EQU 10
    INIT	EQU 15
    DOUBLE	EQU 20
;const
    UPCOUNT	EQU 60
    PRESSCOUNT	EQU 100
    PRESSADD	EQU 100
trans_judge_action:
    MOVLW   MULTI
    XORWF   cur_key, w
    BTFSC   STATUS, 2
    GOTO    action_multi	;multi
    MOVLW   NOKEY		;continue
    XORWF   cur_key, w
    BTFSC   STATUS, 2
    GOTO    action_up_timeout	;up
    MOVF    last_key, w		;down
    XORWF   cur_key, w
    BTFSC   STATUS, 2
    GOTO    action_same_timeout ;same
    GOTO    action_other	 ;other
;    
action_multi:
    MOVLW   MULTIKEY
    GOTO    do_transfer
action_up_timeout:
    MOVLW   WAIT
    XORWF   state, w
    BTFSS   STATUS, 2
    GOTO    action_up	    ;not wait
    INCF    wait_count	    ;waiting
    MOVLW   UPCOUNT
    XORWF   wait_count, w
    BTFSS   STATUS, 2
    GOTO    action_up
    GOTO    action_timeout
    
action_up:
    MOVLW   UP
    GOTO    do_transfer    
action_same_timeout:
    MOVLW   CLICK
    XORWF   state, w
    BTFSS   STATUS, 2
    GOTO    action_same
    INCF    click_count
    MOVLW   PRESSCOUNT
    XORWF   click_count, w
    BTFSS   STATUS, 2
    GOTO    action_same
    GOTO    action_timeout
action_same:
    MOVLW   SAME
    GOTO    do_transfer
action_timeout:
    MOVLW   TIMEOUT
    GOTO    do_transfer     
action_other:
    MOVLW   OTHER
    GOTO    do_transfer
       
do_transfer:
    MOVWF   action
    CLRF    event
    
    MOVF    state, w
    addlw   1
    ADDWF   action, f
    MOVLW   INIT+1
    SUBWF   action, w
    BTFSC   STATUS, 0
    GOTO    change_state ;no carry -> state+action+1>=INIT+1
    movlp   high(event_table)
    MOVLW   low(event_table)
    ADDWF   action, w
    BTFSC   STATUS, 0
    INCF    PCLATH
    CALL    event_table  ;get next state
    MOVWF   event
change_state:
    movlp   high(action_table)
    MOVLW   low(action_table)
    ADDWF   action, w
    BTFSC   STATUS, 0
    INCF    PCLATH
    CALL    action_table  ;get next state
    MOVWF   state

clear_count_judge:
    MOVF    event, f
    BTFSC   STATUS, 2
    GOTO    transfer_final ;event == 0

clear_count:
    CLRF    wait_count
    CLRF    click_count

transfer_final:
    banksel swap
    MOVF    last_key, w
    MOVWF   swap
    
    MOVWF   cur_key, w
    BTFSS   STATUS, 2
    MOVWF   last_key
    
    MOVF    swap, w
    MOVWF   cur_key
    
display:
    MOVF    event, f
    BTFSC   STATUS, 2
    RETFIE
    banksel dis_last_key
    MOVF    dis_last_key, W
    XORWF   cur_key, W
    BTFSC   STATUS, 2
    GOTO    display_judge_event
display_change:
    banksel dis_count
    CLRF    dis_count
    CLRF    dis_count+1
    MOVF    cur_key, W
    banksel dis_last_key
    MOVWF   dis_last_key
display_judge_event:
    banksel dis_count
    MOVLW   3
    SUBWF   event, W
    BTFSS   STATUS, 0
    GOTO    event_1_2   ;if carry -> event<3
    MOVLW   3
    XORWF   event, W
    BTFSC   STATUS, 2
    GOTO    event_3
    GOTO    display_final

event_1_2:
    MOVF    event,W
    ADDWF   dis_count, F
    GOTO    display_final
event_3:
    INCF    press_count
    MOVLW   PRESSADD
    XORWF   press_count, W
    BTFSC   STATUS, 2
    GOTO    event_3_add_count
    GOTO    display_final

event_3_add_count:
    INCF    dis_count
    CLRF    press_count

display_final:
    MOVF   cur_key, W
    MOVWF   dis_cache
    MOVF    event,W
    MOVWF   dis_cache+1
    MOVLW   10
    SUBWF   dis_count, W
    BTFSS   STATUS, 0
    GOTO    display_count   ;if carry
display_count_carry:
    INCF    dis_count+1
    MOVLW   10
    SUBWF   dis_count, F
    SUBWF   dis_count+1, W
    BTFSC   STATUS, 0
    CLRF    dis_count+1	;if no carry
display_count:
    MOVF    dis_count, W
    MOVWF   dis_cache+3
    MOVF    dis_count+1, W
    MOVWF   dis_cache+2
    
    RETFIE

	
;MAIN FUNCTION
psect   main,class=CODE,delta=2 ; PIC10/12/16   
global _main
_main:
    
;Timer0 configuration
BANKSEL T0CON0
MOVLW 0b00010000;set Timer0 in 16bit mode,post:1:8
MOVWF T0CON0
BANKSEL T0CON1
MOVLW 01000000;FOCS/4,synchronized to FOSC/4,pre:1:1
MOVWF T0CON1
BANKSEL TMR0L
MOVLW 0xfe
MOVWF TMR0H
MOVLW 0x0c
MOVWF TMR0L;init the TMR0 offset

    
;interrupt configuration
BANKSEL PIR0
BCF PIR0,5;clear the timer signal bit
banksel INTCON
BSF INTCON,0;INT enable
BSF INTCON,7;global enable
banksel PIE0
BSF PIE0,5;timer0_interrupt enable


;start timing
BANKSEL T0CON0
BSF T0CON0,7; enable Timer0


;init PORTA / PORTB / PORTC
BANKSEL PORTA 
CLRF PORTA ;Init PORTA
BANKSEL LATA ;Data Latch
CLRF LATA 
BANKSEL ANSELA 
CLRF ANSELA ;digital I/O
BANKSEL TRISA 
CLRF TRISA

BANKSEL LATB ;Data Latch
CLRF LATB
BANKSEL ANSELB 
CLRF ANSELB ;digital I/O
 
BANKSEL PORTC
BANKSEL PORTC
CLRF PORTC ;Init PORTC
BANKSEL LATC ;Data Latch
CLRF LATC
BANKSEL ANSELC
CLRF ANSELC ;digital I/O
BANKSEL TRISC
CLRF TRISC


;init variables
CLRF dis_cache
CLRF dis_cache + 1
CLRF dis_cache + 2
CLRF dis_cache + 3
CLRF last_result
CLRF count
CLRF action
MOVLW 15
MOVWF state
CLRF wait_count
CLRF click_count
CLRF last_key
CLRF index
CLRF cur_key
BANKSEL led_select
CLRF led_select
CLRF i
CLRF j
CLRF dis_last_key
CLRF dis_count
CLRF swap
CLRF press_count
CLRF workplace2


;MAIN
LOOP:
;code_sel
MOVLW HIGH(code_table)
MOVWF PCLATH      
MOVLW LOW(code_table)
BANKSEL led_select
ADDWF led_select, W
BTFSS STATUS, 0
GOTO CALL_TABLE
INCF PCLATH
CALL_TABLE:
ADDLW 1
CALL code_table
BANKSEL PORTA 
MOVWF PORTA


;seq_sel
MOVLW HIGH(seq_table)
MOVWF PCLATH  
;w = dis_cache + offset
MOVLW   high(dis_cache)
MOVWF   FSR0H
MOVLW   low(dis_cache)
BANKSEL led_select
ADDWF   led_select, w
MOVWF   FSR0L
MOVF    INDF0, w
;seq_table[dis_cache + offset]
CALL seq_table
MOVWF PORTC   

    
;led_select = (led_select + 1) mod 4
BANKSEL led_select
INCF led_select,f
MOVLW 0b11
ANDWF led_select,f

    
;delay
MOVLW 2
MOVWF delay2
DELAY1:
MOVLW 0xff
MOVWF delay1
DECFSZ delay1,f
GOTO $-1
DECFSZ delay2,f
GOTO DELAY1

    
;end seq_select
CLRF PORTC

    
GOTO LOOP
    
end reset_vec